import type { FullModelInfo, SupplierInfo, ModelSetting, ModelInfo } from './type'
import { ChatStoreName, StorageKey } from '@/provider/storage/enum'
import StorageProvider from '@/provider/storage'
import LLMProvider from '@/provider/llm'
import $config from '@/config'
import { turnFullModelInfo } from './hooks/utils'

/**
 * 模型服务类
 *
 * @description 管理模型与提供商相关功能
 */
class xModelService {
  // 静态属性存储唯一实例
  private static instance: xModelService

  // 本地提供商信息
  private localSuppliers: SupplierInfo[] = []

  /**
   * 服务初始化（全局仅执行一次）
   */
  private constructor() {
    // 当前版本提供商不可编辑，因此可以在初始化时直接获取，一劳永逸
    const confSuppliers = $config.llm.suppliers()
    for (const item of confSuppliers) {
      // 保证ID不会重复
      if (item.id && !this.localSuppliers.some((supplier) => supplier.id === item.id)) {
        const provider = item.provider ?? item.id
        if (provider && $config.llm.provider[provider]) {
          // 已存在定义
          this.localSuppliers.push({
            id: item.id,
            provider,
            name: item.name ?? item.id,
            baseUrl: item.baseUrl,
            apiKey: item.apiKey,
            isActive: !!item.isActive,
          })
        } else {
          window.console.warn(`Supplier provider '${item.provider}' is undefined, ignored!`)
        }
      } else if (item.id) {
        window.console.warn(`Supplier ID '${item.id}' is duplicated, ignored!`)
      }
    }
  }

  /**
   * 获取提供商provider实例
   *
   * @param supplierId 提供商ID
   * @returns
   */
  public getProviderInstance = (supplierId: string) => {
    const info = this.getSupplierById(supplierId)
    if (info) {
      return LLMProvider.instance(info.provider, {
        baseUrl: info.baseUrl,
        apiKey: info.apiKey,
      })
    }
    return null
  }

  /**
   * 获取单例实例
   *
   * @returns
   */
  public static getInstance = () => {
    if (!xModelService.instance) {
      xModelService.instance = new xModelService()
    }
    return xModelService.instance
  }

  /**
   * 提供商连接检测
   *
   * @param supplierId 提供商ID
   * @param timeout 超时时间（毫秒）
   * @returns
   */
  public connectSupplierById = async (supplierId: string, timeout: number = 5000) => {
    const provider = await this.getProviderInstance(supplierId)
    if (provider) {
      return await Promise.race([
        provider.check(),
        new Promise<boolean>((_, reject) =>
          setTimeout(() => reject(new Error('服务器访问超时')), timeout),
        ),
      ])
    }
  }

  /**
   * 获取完整提供商列表
   *
   * @returns
   */
  public getSuppliersHistory = () => {
    return this.localSuppliers
  }

  /**
   * 获取指定提供商
   *
   * @param supplierId 提供商ID
   * @returns
   */
  public getSupplierById = (supplierId: string) => {
    return this.localSuppliers.find((item) => item.id === supplierId)
  }

  /**
   * 刷新指定提供商的模型列表
   * 并同步更新本地数据
   *
   * @param supplierId 提供商ID
   * @requires
   */
  public refreshModelsWithProvider = async (supplierId: string) => {
    // 本次更新的模型
    const response: ModelInfo[] = []
    const provider = await this.getProviderInstance(supplierId)
    if (provider) {
      // 读取本地模型
      const db = await StorageProvider.DBChatInstance<ModelInfo>(ChatStoreName.Models)
      const localModels = await db.getAll()
      // 读取提供商模型
      const supplierModels = await provider.getModels()
      for (const model of supplierModels) {
        // 防止ID重复，统一增加前缀
        const id = `${supplierId}:${model.key}`
        response.push({
          id,
          key: model.key,
          type: model.type,
          supplierId,
          name: model.name,
          size: model.size,
          toolUse: !!model.toolUse,
          vision: !!model.vision,
          // 继承状态
          inUse: !!localModels.find((item) => item.id === id)?.inUse,
        })
      }
      // 更新数据，同时移除不存在的数据
      await db.set(response)
      const updatedIds = response.map((model) => model.id)
      const removedIds = localModels
        .filter((item) => item.supplierId === supplierId && !updatedIds.includes(item.id))
        .map((item) => item.id)
      await db.delete(removedIds)
    }
    return response
  }

  /**
   * 获取完整模型列表
   *
   * @param type 模型类型
   * @returns
   */
  public getModelsHistory = async (type?: ModelType) => {
    const response: FullModelInfo[] = []
    // 读取存储的模型
    const db = await StorageProvider.DBChatInstance<ModelInfo>(ChatStoreName.Models)
    const models = await db.getAll()
    const suppliers = this.getSuppliersHistory()
    for (const model of models) {
      // 根据请求条件过滤
      if (!type || model.type === type) {
        const supplier = suppliers.find((item) => item.id === model.supplierId)
        if (supplier) {
          response.push(turnFullModelInfo(model, supplier))
        }
      }
    }
    // 按照suppliers中顺序排序
    response.sort((a, b) => {
      const aIndex = suppliers.findIndex((s) => s.id === a.supplier.id)
      const bIndex = suppliers.findIndex((s) => s.id === b.supplier.id)
      return aIndex - bIndex
    })
    return response
  }

  /**
   * 获取指定模型信息
   *
   * @param modelId 模型ID
   * @returns
   */
  public getModelById = async (modelId: string) => {
    const db = await StorageProvider.DBChatInstance<ModelInfo>(ChatStoreName.Models)
    const model = await db.get(modelId)
    if (model) {
      const supplier = this.getSupplierById(model.supplierId)
      return turnFullModelInfo(model, supplier)
    }
  }

  /**
   * 修改指定模型信息
   *
   * @param modelId 模型ID
   * @param data 模型数据（支持片段更新）
   * @returns
   */
  public setModelInfo = async (modelId: string, data: Partial<Omit<ModelInfo, 'id'>>) => {
    const db = await StorageProvider.DBChatInstance<ModelInfo>(ChatStoreName.Models)
    const model = await db.get(modelId)
    if (!model) {
      throw new Error('未找到模型信息')
    }
    // 保证ID不会变更
    Object.assign(model, data, { id: modelId })
    await db.set(model)
    return model
  }

  /**
   * 清空全部模型
   *
   * @returns
   */
  public clearAllModels = async () => {
    const db = await StorageProvider.DBChatInstance<ModelInfo>(ChatStoreName.Models)
    return db.clear()
  }

  /**
   * 获取当前模型
   *
   * @returns
   */
  public getActiveModel = async () => {
    const modelId = StorageProvider.getLocalStorage<string>(StorageKey.ActiveModel)
    if (modelId) {
      const db = await StorageProvider.DBChatInstance<ModelInfo>(ChatStoreName.Models)
      const model = await db.get(modelId)
      if (model) {
        const supplier = this.getSupplierById(model.supplierId)
        return turnFullModelInfo(model, supplier)
      }
    }
  }

  /**
   * 修改当前模型
   *
   * @param modelId 模型ID
   * @returns
   */
  public setActiveModel = (modelId: string) => {
    return StorageProvider.setLocalStorage<string>(StorageKey.ActiveModel, modelId)
  }

  /**
   * 读取模型设置信息
   *
   * @returns
   */
  public readModelSetting = () => {
    return StorageProvider.getLocalStorage<ModelSetting>(StorageKey.ModelSetting, {
      // 填充默认值（未存储时）
      prompt: '',
      temperature: 0.7,
      limitMaxTokens: false,
      maxTokens: 2046,
    })
  }

  /**
   * 写入模型设置信息
   *
   * @param data 数据
   * @returns`
   */
  public saveModelSetting = (data: ModelSetting) => {
    data.temperature = Math.max(0, Math.min(1, data.temperature))
    return StorageProvider.setLocalStorage(StorageKey.ModelSetting, data)
  }
}

export default xModelService
